package sc.digital.human;

import javax.swing.*;
import java.awt.*;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;

public class Talk extends JScrollPane {
    private final DefaultListModel<JPanel> dataModel = new DefaultListModel<>();
    private final JList<JPanel> talks = new JList<>();
    private final JScrollBar scrollBar;

    public Talk() {
        super.setViewportView(this.talks);
        this.scrollBar = super.getVerticalScrollBar();
        this.talks.setModel(this.dataModel);
        this.talks.setCellRenderer(new TalkCell());
        this.talks.setBackground(Color.LIGHT_GRAY);
    }

    /**
     * 交谈
     *
     * @param text   交谈文本
     * @param ipName 回答对象，回答对象为空时是提问反之回答
     */
    public void talk(String text, Human.IPName ipName, float audioSeconds) {
        SwingUtilities.invokeLater(() -> {
            Say say = new Say(ipName, text, super.getWidth());
            this.dataModel.addElement(new TalkRoom(ipName, new SayRoom(ipName, new Man(ipName), say)));
            if (audioSeconds > 0) {
                this.talk(say, text, super.getWidth(), audioSeconds);
            }
            SwingUtilities.invokeLater(() -> this.scrollBar.setValue(this.scrollBar.getMaximum()));
        });
    }

    void talk(Say say, String text, int width, float audioSeconds) {
        StringBuffer speaking = new StringBuffer();
        AtomicInteger speaks = new AtomicInteger(0);
        Timer timer = new Timer(0, null);
        timer.setDelay((int) (audioSeconds * 1000) / text.length());//计算每个字需要的时间（毫秒）=音频时长（毫秒）/文字长度
        timer.addActionListener((e) -> {
            if (speaks.intValue() >= text.length()) {
                timer.stop();
            } else {
                speaking.append(text, speaks.intValue(), speaks.incrementAndGet());
                say.setText((say.getFontMetrics(say.getFont()).stringWidth(text) < super.getWidth())
                        ? String.format("<html>%s<html>", speaking)
                        : String.format("<html><div style='width:%dpx;'>%s</div></html>", (width / 2), speaking));
                say.repaint();
                talks.repaint();
            }
        });
        timer.start();
    }

    static class TalkRoom extends JPanel {
        public TalkRoom(Human.IPName ipName, SayRoom sayRoom) {
            this.setOpaque(false);
            this.setLayout(new BorderLayout());
            this.add(sayRoom, ipName != null ? BorderLayout.WEST : BorderLayout.EAST);
            this.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
        }
    }

    static class SayRoom extends JPanel {
        public SayRoom(Human.IPName ipName, Man man, Say say) {
            super.setOpaque(false);
            super.setLayout(new BorderLayout());
            super.add(man, ipName != null ? BorderLayout.WEST : BorderLayout.EAST);
            super.add(say, BorderLayout.CENTER);
        }
    }

    static class Say extends JLabel {
        public Say(Human.IPName ipName, String text, int width) {
            super.setOpaque(true);
            super.setForeground(Color.BLACK);
            super.setBackground(ipName != null ? Color.WHITE : Color.GREEN);
            super.setHorizontalAlignment(ipName != null ? JLabel.LEFT : JLabel.RIGHT);
            super.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
            super.setText((super.getFontMetrics(super.getFont()).stringWidth(text) < width)
                    ? String.format("<html>%s<html>", text)
                    : String.format("<html><div style='width:%dpx;'>%s</div></html>", (width / 2), text));
        }
    }

    static class Man extends JLabel {
        static final ImageIcon LOGO = new ImageIcon(Config.LOGO.getScaledInstance(32, 32, Image.SCALE_SMOOTH));
        static Map<Human.IPName, ImageIcon> ICON = new HashMap<Human.IPName, ImageIcon>() {{
            for (Human.IPName ipName : Human.IPName.values()) {
                this.put(ipName, new ImageIcon(ipName.image.getScaledInstance(-1, 32, Image.SCALE_SMOOTH)));
            }
        }};

        public Man(Human.IPName ipName) {
            super(ipName != null ? ICON.get(ipName) : LOGO, JLabel.CENTER);
            super.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
        }
    }

    static class TalkCell implements ListCellRenderer<JPanel> {
        @Override
        public Component getListCellRendererComponent(JList<? extends JPanel> list, JPanel value, int index, boolean isSelected, boolean cellHasFocus) {
            return value;
        }
    }
}
